from functionBinding import functionBinding
from functionDef import functionDef
from Return import Return
from builtin import *
from varRef import varRef
from expression import environment
from customExceptions import ReturnExcpt

class interpreter:
	def __init__(self,program):
		self.env = environment("+",functionDef("+", ["a","b"], Return(plus(varRef("a"),varRef("b")))), None)
		self.env = environment("-",functionDef("-", ["a","b"], Return(minus(varRef("a"),varRef("b")))), self.env)
		self.env = environment("*",functionDef("*", ["a","b"], Return(mult(varRef("a"),varRef("b")))), self.env)
		self.env = environment("/",functionDef("/", ["a","b"], Return(div(varRef("a"),varRef("b")))), self.env)
		self.env = environment("<",functionDef("<", ["a","b"], Return(lessThan(varRef("a"),varRef("b")))), self.env)	
		self.env = environment(">",functionDef(">", ["a","b"], Return(greatThan(varRef("a"),varRef("b")))), self.env)
		self.env = environment("<=",functionDef("<=", ["a","b"], Return(lessEq(varRef("a"),varRef("b")))), self.env)
		self.env = environment(">=",functionDef(">+", ["a","b"], Return(greatEq(varRef("a"),varRef("b")))), self.env)
		self.env = environment("and",functionDef("and", ["a","b"], Return(and_(varRef("a"),varRef("b")))), self.env)
		self.env = environment("or",functionDef("or", ["a","b"], Return(or_(varRef("a"),varRef("b")))), self.env)
		self.env = environment("not",functionDef("not", ["a"], Return(not_(varRef("a")))), self.env)
		self.env = environment("string-length",functionDef("strlen", ["str"], Return(strlen(varRef("str")))), self.env)
		self.env = environment("substring",functionDef("substr", ["str", "s", "e"], 
			Return(substr(varRef("str"),varRef("s"),varRef("e")))), self.env)
		self.env = environment("string=?",functionDef("string=?", ["str1", "str2"],
			Return(strEq(varRef("str1"),varRef("str2")))), self.env)
		self.env = environment("string<?",functionDef("string<?", ["str1", "str2"],
			Return(strLess(varRef("str1"),varRef("str2")))), self.env)
		self.env = environment("==",functionDef("==", ["a","b"], Return(equals(varRef("a"),varRef("b")))), self.env)
		self.env = environment("integer?",functionDef("int?", ["a"], Return(intQ(varRef("a")))), self.env)
		self.env = environment("boolean?",functionDef("bool?", ["a"], Return(boolQ(varRef("a")))), self.env)
		self.env = environment("floating-point?",functionDef("float?", ["a"], Return(floatQ(varRef("a")))), self.env)
		self.env = environment("void?",functionDef("void?", ["a"], Return(voidQ(varRef("a")))), self.env)
		self.env = environment("string?",functionDef("string?", ["a"], Return(stringQ(varRef("a")))), self.env)
		self.env = environment("instanceof",functionDef("instanceof", ["obj","val"], 
			Return(instanceof(varRef("obj"),varRef("val")))), self.env)
		self.env = environment("closure?",functionDef("closure?", ["a"], Return(closureQ(varRef("a")))), self.env)
		self.env = environment("plain?",functionDef("plain?", ["a"], Return(plainQ(varRef("a")))), self.env)
		self.env = environment("print",functionDef("print", ["a"], printOut(varRef("a"))), self.env)
		self.env = environment("read-line",functionDef("read", [], Return(readLine())), self.env)

		self.program = program
                
	def execute(self):
		try:
			self.program.evaluate(self.env) #you wouldn't return this normally
		except ReturnExcpt, r:
			return r.getValue()
